package cn.aezo.minions.gen;

import cn.aezo.minions.gen.datasource.DataSourceService;
import cn.aezo.minions.gen.model.ProjectConfig;
import cn.aezo.minions.gen.model.Template;
import cn.aezo.utils.base.MiscU;
import lombok.Data;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author smalle
 * @date 2019-07-31 11:36
 */
@Data
public class Context implements Contextable {
    /**
     * 代码生成项目配置
     */
    private ProjectConfig projectConfig;

    private DataSourceService ds;

    /**
     * 生成项目根目录: D:/temp/minions
     */
    private String rootDir;

    /**
     * 生成项目根目录: /1/demo
     */
    private String projectDir;

    public String currentModule;
    public static final String BackendModule = "backend";
    public static final String FrontendModule = "frontend";

    /**
     * 模板树
     */
    Template template;

    private Map<String, Object> ext = new HashMap<>();

    public static Context init(ProjectConfig projectConfig, Template template) {
        Context context = new Context();

        context.setProjectConfig(projectConfig);
        context.setTemplate(template);

        // 获取数据源链接
        DataSourceService ds = DataSourceService.getInstance(context.getProjectConfig());
        context.setDs(ds);

        context.initDirContext();

        return context;
    }

    public void initDirContext() {
        // TODO
        // this.rootDir = System.getProperty("user.dir") + /minions_out/;
        this.rootDir = "D:/temp/minions_out/";
        this.projectDir = projectConfig.getUserId() + "/" + projectConfig.getProjectName();
    }

    public String getProjectRootDir() {
        return rootDir + projectDir;
    }

    public String getModuleRootDir() {
        return "".equals(this.getCurrentModule()) ? (rootDir + projectDir) : (rootDir + projectDir + "/" + this.getCurrentModule());
    }

    /**
     * 从 Context 对象中获取配置，以供模板渲染使用
     * @return
     */
    @Override
    public Map<String, Object> getContextMap() {
        Map<String, Object> map = MiscU.Instance.toMap("projectConfig", projectConfig,
                "rootDir", rootDir, "projectDir", projectDir, "currentModule", currentModule,
                "template", template);

        // 如果ext中的对象为Contextable，则将其属性提升到一级key中
        Set<String> keys = new HashSet<>();
        keys.addAll(map.keySet());
        map.putAll(getExtContextMap(keys, ext));
        return map;
    }

    /**
     * 获取 Context.ext 扩展属性配置
     * @param keys
     * @param ext
     * @return
     */
    public Map<String, Object> getExtContextMap(Set<String> keys, Map<String, Object> ext) {
        Map<String, Object> map = new HashMap<>();
        for (Map.Entry<String, Object> entry : ext.entrySet()) {
            if(entry.getValue() instanceof Contextable) {
                Contextable contextable = (Contextable) entry.getValue();
                Map<String, Object> itemMap = contextable.getContextMap();
                if(itemMap == null || itemMap.keySet().size() == 0) continue;
                for (String key : keys) {
                    if(itemMap.keySet().contains(key)) {
                        throw new IllegalStateException("重复的参数名");
                    }
                }

                // 属性直接放置到一级key中
                map.putAll(itemMap);
                keys.addAll(map.keySet());
            } else {
                if(keys.contains(entry.getKey())) {
                    throw new IllegalStateException("重复的参数名");
                }
                map.put(entry.getKey(), entry.getValue());
            }
        }
        return map;
    }
}
